#include<iostream>
#include<stdio.h>
#include<vector>
#include<pthread.h>
#include <semaphore.h>

using namespace std;

//环形队列-----信号量

#define MAX_QUEUE 5


template<class T>
class RingQueue{
  private:
    vector<T> _array;
    int _read_step;
    int _write_step;
    int _capacity;
    sem_t _sem_idle;   //空闲空间计数器，当消费者进行读取数据之后进行 V 操作
    sem_t _sem_data;   //数据空间计数器，当生产者增加一个数据进行 V 操作
    sem_t _sem_lock;   //用来实现互斥
 
  public:
    RingQueue(int capacity = MAX_QUEUE):_capacity(capacity),_array(capacity),_read_step(0),_write_step(0)
  {
 //int sem_init(sem_t *sem, int pshared, unsigned int value);  //第一个参数为计数器，第二个参数：0-线程间，!0-进程间，第三个参数：初始化值
    sem_init(&_sem_idle,0,capacity);  //空闲空间初始化为 capacity  
    sem_init(&_sem_data,0,0);
    sem_init(&_sem_lock,0,1);    //锁资源，初始化为 1 实现互斥
  }
    ~RingQueue()
    {
      //销毁计数器资源
      sem_destroy(&_sem_idle);
      sem_destroy(&_sem_data);
      sem_destroy(&_sem_lock);
    }
    bool Push(const T& data)
    {
      //判断有无空闲空间，没有则阻塞
      sem_wait(&_sem_idle);

      //加锁
      sem_wait(&_sem_lock);
     //加锁要放到判断有无空间之后，倘若放在前边会导致没有空闲空间时候线程阻塞而没有解锁操作

      //存入数据
      _array[_write_step]=data;
      _write_step=(_write_step+1)%_capacity;
      sem_post(&_sem_data); //对数据空间的资源+1，唤醒一个消费者
      sem_post(&_sem_lock);  //解锁
      return true;
    }
    bool Pop(T* data)
    {
      sem_wait(&_sem_data);  //判断有无数据，没有则阻塞

      sem_wait(&_sem_lock); //加锁
      
      //删除一个数据
      *data=_array[_read_step];
      _read_step=(_read_step+1)%_capacity;
      sem_post(&_sem_idle);  //对空闲空间+1，唤醒一个生产者  
      sem_post(&_sem_lock);  //解锁
      return true;
    }
};



#define MAX_USER 5

void* consumer(void* arg)
{
  RingQueue<int> *q=(RingQueue<int> *)arg;
  while(1){
    //消费者读取数据
    int data;
    q->Pop(&data);
    printf("%p 线程获取到了数据-------- %d\n",pthread_self(),data);
  }
  return NULL;
}

void* productor(void* arg)
{
  RingQueue<int> *q=(RingQueue<int> *)arg;
  int data=0;
  while(1){
    //生产者进行数据的获取
    q->Push(data);
    printf("%p 线程入队了数据 : %d\n",pthread_self(),data++);
  }
  return NULL;
}

int main()
{
  RingQueue<int> q;
  pthread_t con_tid[MAX_USER],pro_tid[MAX_USER];
  int ret;
 
  //线程创建
  for(int i=0;i<MAX_USER;++i){
    ret=pthread_create(&con_tid[i],NULL,consumer,(void*)&q);
    if(ret!=0){
      perror("pthread_creat error!\n");
      return -1;
    }
    ret=pthread_create(&pro_tid[i],NULL,productor,(void*)&q);
    if(ret!=0){
      perror("pthread_creat error!\n");
      return -1;
    }
  }

  //线程等待
  for(int i=0;i<MAX_USER;++i){
    pthread_join(con_tid[i],NULL);
    pthread_join(pro_tid[i],NULL);
  }

  return 0;
}




